package com.sinodata.bsm.center.engine.event.correlation;

import java.util.*;

import org.apache.commons.lang.StringUtils;

import com.sinodata.bsm.center.bean.RelationHelper;
import com.sinodata.bsm.center.bean.ResBean;
import com.sinodata.bsm.center.cache.EventCorrelationLinkCache;
import com.sinodata.bsm.center.cache.EventTypeCache;
import com.sinodata.bsm.center.cache.NewEventCache;
import com.sinodata.bsm.center.expression.Expressions;
import com.sinodata.bsm.center.util.spring.SpringContextHolder;
import com.sinodata.bsm.common.vo.Event;
import com.sinodata.bsm.common.vo.EventCorrelation;
import com.sinodata.bsm.common.vo.EventCorrelationLink;
import com.sinodata.bsm.common.vo.EventCorrelationPolicy;
import com.sinodata.bsm.common.vo.EventType;

/**
 * 
 * <p>
 * Description: 策略关联处理器
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-6-13 PM 2:17:34     liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
public class ECPHandler {

    NewEventCache newEventCache = SpringContextHolder.getBean(NewEventCache.class);;

    EventCorrelationLinkCache eventCorrelationLinkCache = SpringContextHolder.getBean(EventCorrelationLinkCache.class);;

    EventTypeCache eventTypeCache = SpringContextHolder.getBean(EventTypeCache.class);;

    //private static Logger logger = Logger.getLogger(ECPHandler.class);

    protected EventCorrelationPolicy ecp;

    protected EventCorrelationLink[] eventCorrelationLinks;

    protected EventType[] subEventArray;

    protected int notifyDelayTime = 0;

    //全局实例集，来自ecmanager
    private Map<String, ECPInstance> ecpInstanceMap;

    public static int NOTIFY_MUST = 0;
    public static int NOTIFY_NO = -1;
    public static int NOTIFY_DEFAULT = 1;

    /**
     * 处理事件，核心入口
     * 返回需要入库的关联信息
     * @param event
     * @return
     */
    public synchronized List<EventCorrelation> handleEvent(Event event) {
        if (!isSubEvent(event.getEventTypeId()) && event.getEventTypeId() != ecp.getMainEventType().longValue()) {
            return null;
        }
        List<EventCorrelation> retList = new ArrayList<EventCorrelation>();
        notifyDelayTime = NOTIFY_DEFAULT;

        if (event.getEventTypeId() == ecp.getMainEventType().longValue()) {
            List<EventCorrelation> matchList = matchMainEvent(event);
            if (matchList != null) {
                retList.addAll(matchList);
            }
        } else {
            List<EventCorrelation> matchListSub = matchSubEvent(event);
            if (matchListSub != null) {
                retList.addAll(matchListSub);
            }
        }
        return retList;
    }

    /**
     * 获取策略
     * @return
     */
    public EventCorrelationPolicy getEcp() {
        return ecp;
    }

    /**
     * 设置策略、装配模型
     * 
     * @param ecp
     */
    public synchronized void setEcp(EventCorrelationPolicy ecp) {
        this.ecp = ecp;

        List<EventCorrelationLink> list = eventCorrelationLinkCache.getByPolicy(ecp.getId());
        //设置从事件关联link
        this.eventCorrelationLinks = list.toArray(new EventCorrelationLink[list.size()]);
        //设置从事件类别
        this.subEventArray = new EventType[eventCorrelationLinks.length];
        suitableSubEvtType.clear();
        for (int i = 0; i < eventCorrelationLinks.length; i++) {
            suitableSubEvtType.add(eventCorrelationLinks[i].getEventTypeLinkId());
            subEventArray[i] = eventTypeCache.get(eventCorrelationLinks[i].getEventTypeLinkId().longValue());
        }

        if (!isSimpleConf()) {
            //有额外配置
            String[] groups = StringUtils.split(ecp.getExtendConfig(), "||");
            for (int k = 0; k < groups.length; k++) {
                Set<Long> set = new HashSet<Long>();
                String[] es = StringUtils.split(groups[k], "&&");
                for (int i = 0; i < es.length; i++) {
                    for (int j = 0; j < list.size(); j++) {
                        if (list.get(j).getSerialNumber().equals(es[i])) {
                            set.add(list.get(j).getEventTypeLinkId());
                        }
                    }
                }
                expressList.add(set);
            }
        } else {
            //简单配置
            for (int i = 0; i < subEventArray.length; i++) {
                Set<Long> set = new HashSet<Long>();
                set.add(subEventArray[i].getId().longValue());
                expressList.add(set);
            }
        }
    }

    private List<Set<Long>> expressList = new ArrayList<Set<Long>>();

    private boolean isSimpleConf() {
        return ecp.getExtendConfig() == null;
    }

    private Set<Long> suitableSubEvtType = new HashSet<Long>();

    public boolean isSubEvent(Long eventTypeId) {
        return suitableSubEvtType.contains(eventTypeId.longValue());
    }

    protected List<EventCorrelation> handleInstance(Event event, Long resId, boolean isMainEvent) {
        List<EventCorrelation> retList = new ArrayList<EventCorrelation>();
        //创建或更新策略实例
        String instanceKey = ecp.getId() + "_" + resId;
        ECPInstance ecpInstance = ecpInstanceMap.get(instanceKey);
        if (ecpInstance == null) {
            ecpInstance = new ECPInstance();
            ecpInstance.setEcp(ecp);
            ecpInstance.setId(resId + "");
            ecpInstance.setExpressList(this.expressList);
            ecpInstanceMap.put(instanceKey, ecpInstance);
            if (isMainEvent) {
                notifyDelayTime = NOTIFY_MUST;
                ecpInstance.setMainEvent(event);
            } else {
                if (notifyDelayTime == NOTIFY_DEFAULT) {
                    notifyDelayTime = ecp.getDelay();
                }
                ecpInstance.addSubEvent(event);
            }
            //主从都延迟
            if (notifyDelayTime == NOTIFY_DEFAULT) {
                notifyDelayTime = ecp.getDelay();
            }
            //
        } else {
            //如果主事件被确认了,取消主事件
            if (ecpInstance.getMainEvent() != null && newEventCache.get(ecpInstance.getMainEvent().getId()) == null) {
                ecpInstance.setMainEvent(null);
                ecpInstance.setSaved(false);
                ecpInstance.clearSubEvent();
            }

            if (isMainEvent) {
                //如果主事件已经存在，又来一个相同的，则放进从事件中
                if (ecpInstance.getMainEvent() != null) {
                    notifyDelayTime = NOTIFY_MUST;
                    //不合理
                    ecpInstance.addSubEvent(event);
                } else {
                    notifyDelayTime = NOTIFY_MUST;
                    ecpInstance.setMainEvent(event);
                }
            } else {
                if (notifyDelayTime == NOTIFY_DEFAULT) {
                    //TODO 获取是否延迟， 如果延迟需要获取主事件指标判断的采集周期
                    notifyDelayTime = ecp.getDelay();
                }
                ecpInstance.addSubEvent(event);
            }
        }
        List<Map<Long, List<Event>>> results = ecpInstance.getResults();
        if (isMainEvent) {
            for (Map<Long, List<Event>> map : results) {
                boolean isMatch = true;
                for (List<Event> evts : map.values()) {
                    for (int i = evts.size() - 1; i >= 0; i--) {
                        if (evts.get(i).getStatus() > 1) {
                            evts.remove(i);
                        }
                    }
                    if (evts.size() < 1) {
                        isMatch = false;
                    }
                }
                if (isMatch) {
                    for (List<Event> evts : map.values()) {
                        for (Event evt : evts) {
                            retList.add(generateEC(evt.getId(), ecpInstance.getMainEvent().getId(), ecp.getId()));
                        }
                    }
                    notifyDelayTime = NOTIFY_NO;
                }
            }
        } else if (ecpInstance.getMainEvent() != null) {
            for (int i = 0; i < expressList.size(); i++) {
                Set<Long> eventtypes = expressList.get(i);
                boolean suitable = false;
                for (Long type : eventtypes) {
                    if (type.longValue() == event.getEventTypeId()) {
                        suitable = true;
                        break;
                    }
                }
                if (!suitable) {
                    continue;
                }
                Map<Long, List<Event>> map = results.get(i);
                boolean isMatch = true;
                for (List<Event> evts : map.values()) {
                    for (int j = evts.size() - 1; j >= 0; j--) {
                        if (evts.get(j).getStatus() > 1) {
                            evts.remove(j);
                        }
                    }
                    if (evts.size() < 1) {
                        isMatch = false;
                        break;
                    }
                }
                if (isMatch) {
                    for (List<Event> evts : map.values()) {
                        for (Event evt : evts) {
                            retList.add(generateEC(evt.getId(), ecpInstance.getMainEvent().getId(), ecp.getId()));
                        }
                    }
                    notifyDelayTime = NOTIFY_NO;
                }
            }

        }

        return retList;
    }

    /**
     * 生成指定的事件关联
     * @param eventId
     * @param mainEventId
     * @param ecpId
     * @return
     */
    private EventCorrelation generateEC(Long eventId, Long mainEventId, Long ecpId) {
        if (mainEventId <= 0 || ecpId <= 0) {
            return null;
        }
        EventCorrelation value = new EventCorrelation();
        value.setEventId(eventId);
        value.setMainEventId(mainEventId);
        value.setPolicyId(ecpId);
        value.setCreateTime(new Date());
        return value;
    }

    public int getAlarmDelayTime() {
        return notifyDelayTime;
    }

    public Map<String, ECPInstance> getEcpInstanceMap() {
        return ecpInstanceMap;
    }

    public void setEcpInstanceMap(Map<String, ECPInstance> ecpInstanceMap) {
        this.ecpInstanceMap = ecpInstanceMap;
    }

    /**
     * 匹配主事件
     * 
     * @param event
     * @return
     */
    protected List<EventCorrelation> matchMainEvent(Event event) {
        if (event.getEventTypeId().equals(ecp.getMainEventType())) {
            Long resId = ecp.getResId();
            if (resId != null && !resId.equals(event.getResId())) {
                return null;
            }
            return handleInstance(event, event.getResId(), true);
        }
        return null;
    }

    /**
     * 匹配从事件
     * 
     * @param event
     * @return
     */
    protected List<EventCorrelation> matchSubEvent(Event event) {
        List<EventCorrelation> retList = new ArrayList<EventCorrelation>();
        for (EventCorrelationLink sub : eventCorrelationLinks) {
            //从事件指定资源的情况
            if (sub.getResId() != null) {
                if (sub.getResId().equals(event.getResId()) && sub.getEventTypeLinkId().equals(event.getEventTypeId())) {
                    List<ResBean> resBeans = RelationHelper.fromRec(event.getResId(), sub.getResRelation());
                    for (ResBean resBean : resBeans) {
                        retList.addAll(handleInstance(event, resBean.res().getId(), false));
                    }
                }
                //从事件未指定资源的情况
            } else {
                if (sub.getEventTypeLinkId().equals(event.getEventTypeId())) {
                    List<ResBean> resBeans = RelationHelper.fromRec(event.getResId(), sub.getResRelation());
                    for (ResBean resBean : resBeans) {
                        retList.addAll(handleInstance(event, resBean.res().getId(), false));
                    }
                }
            }
        }
        return retList;
    }

}